package Graficas;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.io.File;
import java.util.ConcurrentModificationException;
import java.util.LinkedList;
import java.util.NoSuchElementException;

import javax.sound.sampled.Clip;

import CargaJuego.Cargador;
import General.Constantes;
import Logica.JuegoLogico;
import Logica.Proyectil;
import Logica.Celdas.Celda;
import Logica.Celdas.Ladrillo;
import Logica.Enemigos.Enemigo;
import Logica.PowerUps.PowerUp;

/**
 * Clase que representa el la parte grafica del juego, aqui se encuentran las operaciones de pintado
 * y de animaciones.
 * 
 * @author Mariano Rodecker
 * @author Matias Varela
 * 
 */
public class JuegoGrafico implements InterfaceGrafica {

	/* ################## ATRIBUTOS DE INSTANCIA ######################## */
	protected JuegoLogico juego;
	protected panelJuego panelGame;

	// matriz de imagenes correspondiente al escenario
	protected Image[][] escenario;

	// Lista que contiene animaciones ejecutandose y que deben ser pintadas
	protected LinkedList<Pintable_Animable> listaAnimaciones;
	protected Audio soundtrack, soundtrackGameOver;

	// variable que indica si la parte grafica ha finalizado o no.
	protected boolean finalizado;

	// variables auxiliares para el pintado, estas variables son globales para
	// la clase y permite mejorar el tiempo de ejecucion del pintado.
	private int desde, hasta, i, j, mov;
	private Celda c;
	private Color colorFondo = new Color(0, 149, 253);

	/* ################## CONSTRUCTORES ######################## */
	/**
	 * Constructor para un juego grafico, carga todos los elementos desde los archivos y crea las
	 * instancias de todos los objetos necesarios.
	 */
	public JuegoGrafico(panelJuego panelGame) {
		Cargador carg = new Cargador(this);
		carg.cargarNivel(1);
		juego = new JuegoLogico(carg.getMario(), carg.getMapaVisible());
		escenario = carg.getEscenario();

		// Cargo los sonidos
		soundtrack = carg.getSoundtrack();
		soundtrackGameOver = carg.getSoundtrack_GameOver();

		listaAnimaciones = new LinkedList<Pintable_Animable>();

		finalizado = false;
		this.panelGame=panelGame;

	}

	/* ################## CONSULTAS ############################# */
	/**
	 * Retorna el juego logico asociado al juego grafico
	 * 
	 * @return el juego logico asociado al juego grafico
	 */
	public JuegoLogico getJuegoLogico() {
		return juego;
	}

	/**
	 * Retorna si el juego grafico finalizo su ejecucion
	 * 
	 * @return true si el juego grafico finalizo su ejecucion; false en otro caso.
	 */
	public boolean isFinalizado() {
		return finalizado;
	}

	/**
	 * Retorna el Audio que se reproduce de fondo.
	 * 
	 * @return el Audio que se reproduce de fondo.
	 */
	public Audio getSoundtrack() {
		return soundtrack;
	}

	/**
	 * Retorna el Audio que se reproduce cuando Mario pierde el juego.
	 * 
	 * @return el Audio que se reproduce cuando Mario pierde el juego.
	 */
	public Audio getSoundtrackGameOver() {
		return soundtrackGameOver;
	}

	/* ################## COMANDOS ######################## */
	/**
	 * Detiene la ejecucion del juego logico asociado.
	 */
	public void detener() {
		juego.detener();
	}

	@Override
	public void hacerUpDownAnimation(Celda celda) {
		UpDownAnimation ani = new UpDownAnimation(celda);
		listaAnimaciones.add(ani);
		ani.start();

	}

	@Override
	public void paint(Graphics g) {
		if (juego.isFinalizado()) {
			if (juego.isLost()) {

				/* REALIZO LOS SONIDOS DE GAME OVER */
				if (soundtrack.isRunning())
					soundtrack.stop();

				if (!soundtrackGameOver.isRunning())
					soundtrackGameOver.reproducir(0);
				try {
					Thread.sleep(4000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}

				/* PINTA LA PANTALLA DE GAME OVER */
				int x, y;
				g.setColor(Color.black);
				g.fillRect(0, 0, Constantes.width_MapaVisible, Constantes.height_MapaVisible);

				g.setColor(Color.white);
				g.setFont(new java.awt.Font("Arial Black", 2, 36));
				x = Constantes.width_MapaVisible / 6;
				y = Constantes.width_MapaVisible / 3;

				g.drawString("GAME OVER !", x, y);
				y = y + Constantes.sizeCelda;
				g.drawImage(juego.getMario().getSprite().getImage(), x, y, null);
				x = x + Constantes.sizeCelda;
				y = y + Constantes.sizeCelda / 2;
				g.setFont(new java.awt.Font("Arial Black", 2, 16));
				g.drawString("Vidas : " + juego.getMario().getVidas(), x, y);
				
				finalizado=true;
				detener();
			} else if (juego.isWin()) {
				/* CORTO LOS SONIDOS */
				if (soundtrack.isRunning())
					soundtrack.stop();

				/* PINTA LA PANTALLA DE WIN */
				int x, y;
				g.setColor(Color.black);
				g.fillRect(0, 0, Constantes.width_MapaVisible, Constantes.height_MapaVisible);

				g.setColor(Color.white);
				g.setFont(new java.awt.Font("Arial Black", 2, 36));
				x = Constantes.width_MapaVisible / 6;
				y = Constantes.width_MapaVisible / 3;

				g.drawString("GANASTE ", x - 10, y);

				try {
					Thread.sleep(2000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				finalizado=true;
				detener();
			}
			else if (juego.isJuegoReintentar()){
				detener();
				panelGame.detener(true,juego.getMario().getVidas()-1,juego.getMario().getPuntos());
			}
		} else {
			/* ********** PINTADO DEL ESCENARIO ********* */
			g.setColor(colorFondo);
			g.fillRect(0, 0, Constantes.width_MapaVisible, Constantes.height_MapaVisible);

			desde = (juego.getMapaVisible().getInicio() / Constantes.sizeCelda);
			hasta = (juego.getMapaVisible().getFin() / Constantes.sizeCelda) + 1;
			if (desde >= 0) {
				for (i = 0; i < juego.getMapaVisible().getMapa().getCantFilas(); i++) {
					for (j = desde; j < hasta; j++) {
						if (escenario[i][j] != null)
							g.drawImage(escenario[i][j], j * Constantes.sizeCelda - juego.getMapaVisible().getInicio(), i * Constantes.sizeCelda, null);
					}
				}
			}

			if (!juego.getMario().isDead()) {
				juego.getMario().getSprite().Draw(g, juego.getMario().getX() - juego.getMapaVisible().getInicio(), juego.getMario().getY());
			}

			/* ********** PINTADO DE LAS ANIMACIONES ********* */
			try {
				for (int i = 0;i<listaAnimaciones.size();i++){
					if (!listaAnimaciones.get(i).isAliveAnimation())
						listaAnimaciones.remove(i);
					else
						listaAnimaciones.get(i).pintar(g, listaAnimaciones.get(i).getCelda().getSprite(), listaAnimaciones.get(i).getCelda().getX() - juego.getMapaVisible().getInicio(), listaAnimaciones.get(i).getCelda().getY());
				}

			} catch (NoSuchElementException e1) {
				System.out.println("error 1.");
			} catch (ConcurrentModificationException e2) {
				System.out.println("error 2.");
			}

			/* ********** PINTADO DEL MAPA VISIBLE ********* */

			// recorro las filas y las columnas y pinto la celda correspondiente a la posicion i,j
			// de la matriz de celdas.
			for (i = 0; i <= juego.getMapaVisible().getMapa().getCantFilas(); i++) {
				for (j = desde; j < hasta; j++) {
					c = juego.getMapaVisible().getMapa().getCelda(i, j);
					if (c != null) {
						if (!c.isInAnimation())
							c.getSprite().Draw(g, c.getX() - juego.getMapaVisible().getInicio(), c.getY());
					}
				}
			}
			try {
				Enemigo e;
				for (int i=0;i<juego.getMapaVisible().getEnemigos().size();i++){
					e=juego.getMapaVisible().getEnemigos().get(i);
					if (e != null) {
						g.drawImage(e.getSprite().getImage(), e.getX() - juego.getMapaVisible().getInicio(), e.getY(), null);

					}
				}
				PowerUp p;
				for (int i=0;i<juego.getMapaVisible().getPowerUps().size();i++){
					p=juego.getMapaVisible().getPowerUps().get(i);
					if (p != null) {
						g.drawImage(p.getSprite().getImage(), p.getX() - juego.getMapaVisible().getInicio(), p.getY(), null);

					}
				}
				Proyectil pr;
				for (int i=0;i<juego.getMapaVisible().getProyectiles().size();i++){
					pr=juego.getMapaVisible().getProyectiles().get(i);
					if (pr != null) {
						g.drawImage(pr.getSprite().getImage(), pr.getX() - juego.getMapaVisible().getInicio(), pr.getY(), null);

					}
				}

			} catch (ConcurrentModificationException ex1) {
				System.out.println("CurrentModificationException");
			}

			/* *********** BARRA DE ESTADO ************************* */
			g.setColor(Color.BLACK);
			g.setFont(new java.awt.Font("Arial Black", 2, 16));
			g.drawString("PUNTOS: " + juego.getMario().getPuntos(), 20,20);
			
			g.drawString("VIDAS: " + juego.getMario().getVidas(), 200,20);
			
			/* *********** FIN PINTADO************************* */
		}
	}

	@Override
	public void hacerAnimacionMonedas(Celda c, SpriteMovementsPrioridad sm, int x, int y) {
		AnimacionMoneda ani = new AnimacionMoneda(c, sm, x - juego.getMapaVisible().getInicio(), y);
		listaAnimaciones.add(ani);
		ani.start();

	}

	@Override
	public void hacerAnimacionRomperLadrillo(Celda c, SpriteMovements sm, int x, int y) {
		AnimacionRomperLadrillo ani = new AnimacionRomperLadrillo(c, sm, x - juego.getMapaVisible().getInicio(), y);
		listaAnimaciones.add(ani);
		ani.start();
	}

}
